package com.ww.java.generic;

import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class SetDemo3 {

    public static void main(String[] args) {
        // Set<?>
        Set<String> stringSet = new HashSet<>(List.of("a", "b"));
        Set<?> wildcardSet = stringSet; // Set<String>可赋值给Set<?>

        // 读操作：安全（读为Object）
        for (Object obj : wildcardSet) {
            System.out.println(obj); // 无论原集合是什么类型，都能转Object
        }

        // 写操作：仅能add null，其他都编译错误
        wildcardSet.add(null); // 合法
//        wildcardSet.add("c"); // 编译错误  Required type: capture of ? Provided: String
//        wildcardSet.add(123); // 编译错误 Required type: capture of ? Provided: int


        // Set<Object>
        Set<Object> objectSet = new HashSet<>();
        // 写操作
        objectSet.add("a");
        objectSet.add(123);
        objectSet.add(BigDecimal.ONE);

        // 读操作
        for (Object obj : objectSet) {
            if (obj instanceof String) {
                String str = (String) obj;
            }
        }

        // 兼容性：Set<String>不能直接赋值给Set<Object>（编译报错）
        Set<String> stringSet2 = new HashSet<>();
        // 泛型不协变，避免类型污染
//        objectSet = stringSet2; // Required type: Set<Object> Provided: Set<String>

        // ------------------------------
        // 核心区别
        // ------------------------------
        /**
         * 1.为什么Set<String>能赋值给Set<?>，却不能赋值给Set<Object>
         * 这是泛型【协变】的核心问题：
         * ①泛型的设计原则：“不允许直接协变”（即Set<String> != Set<Object>的子类），避免“把Integer添加到Set<Object>”，却污染了原Set<String>的情况；
         * ②Set<?>是“只读视图”：编译器禁止添加非null元素，从根源上避免了类型污染，所以允许接收所有Set子类型；
         *
         * 2.方法参数该用Set<?>还是Set<Object>
         * ①如果你只需要【读取】元素，不关心元素类型 -> 用Set<?>（兼容所有Set，类型安全）；
         * ②如果你需要【添加任意类型元素】 -> 用Set<Object>（明确声明存储多种类型，避免误解）；
         *
         * 3.为什么Set<?>不能添加非null元素
         * ①当Set<?>实际是Set<String>时，添加Integer会出错；
         * ②当Set<?>实际是Set<Integer>时，添加String会出错；
         */

    }

    /**
     * 适用场景：需要接收“任意类型的Set”，且只需要读取元素（不修改）
     */
    public static void printSet(Set<?> set) {
        for (Object obj : set) {
            System.out.println(obj);
        }
    }
}
